/**
 * @param { 物品列表 } itemList
 */
export let itemList = [];


/**
 * @param { 上次动画 } lastAnime
 */
export let lastAnime = '';


/**
 * @param { 按键触发 } KEYLIST
 * @param { 触发的数量 } len
 */
export let KEYLIST = {
  'a': false, // Left
  'd': false, // Right
  'w': false, // Forward
  's': false, // Back
  'shift': false, // Running
  ' ': false, // Jump
};


/**
 * @function getItem
 * @param { 物品类型 } type
 * 获取场景中的物品对象
 */
export function getItem(type) {
  let item = itemList.find(obj => obj.type === type);
  return item;
}


/**
 * @function addCamera
 * @param { 摄像机视锥体长宽比 } aspect
 * @param { 摄像机的位置 } position
 * @param { 摄像机视锥体垂直视野角度 } fov
 * @param { 摄像机视锥体近端面 } near
 * @param { 摄像机视锥体远端面 } far
 */
export function addCamera(aspect, position = { x: 0, y: 0, z: 0 }, fov = 100, near = 0.1, far = 1000) {
  // 创建摄像机
  let camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.x = position.x;
  camera.position.y = position.y;
  camera.position.z = position.z;
  itemList.push({ type: 'camera', api: camera });
  return camera;
}


/**
 * @function addControls
 * @param { 摄像机视锥体长宽比 } aspect
 */
export function addControls(camera, domElement, configs = {}) {
  let controls = new THREE.OrbitControls(camera, domElement);
  // 配置
  Reflect.ownKeys(configs).forEach(item => controls[item] = configs[item]);
  itemList.push({ type: 'controls', api: controls });
  return controls;
}


/**
 * @function getKeyAngle
 * @param { 按键 } key
 */
export function getKeyAngle(key = '') {
  let keyAngle = 0;
  if (key.toLowerCase() === `w`) keyAngle = 0;
  else if (key.toLowerCase() === `a`) keyAngle = Math.PI / 2;
  else if (key.toLowerCase() === `s`) keyAngle = Math.PI
  else if (key.toLowerCase() === `d`) keyAngle = 3 * Math.PI / 2
  else keyAngle = null;
  return keyAngle;
}


/**
 * @function refreshKeyAngle
 * @param { 按键 } key
 */
export function refreshKeyAngle(key) {
  // 合并操作值
  let keyAngle = 0;
  let moveNum = 0;

  // 非方向键操作
  if (key !== `w` && key !== `a` && key !== `s` && key !== `d`) return null;

  // 方向键获取角度
  for (let direction in KEYLIST) {
    // 如果是两种相反的方向键, 则以最新的方向更新动作, 隔离3种按键的情况
    if (KEYLIST.w && KEYLIST.s || KEYLIST.a && KEYLIST.d) {
      keyAngle = getKeyAngle(key);
      moveNum += 1;
      break;
    };
    // 如果是其它方向键的多个按键
    if (KEYLIST[direction]) {
      if (direction === `w` || direction === `a` || direction === `s` || direction === `d`) {
        moveNum += 1;
        keyAngle += getKeyAngle(direction);
      }
    }
  }
  // ↙方向特殊处理
  if (KEYLIST.w && KEYLIST.d) keyAngle += 2 * Math.PI
  keyAngle = moveNum === 0 ? null : keyAngle / moveNum;
  return keyAngle;
}


/**
 * @function loadAnime
 * @param { 混合器对象 } Mixer
 * @param { 对象字符串 } item
 * @param { 动画名称 } anime
 * @param { 动画时长 } duration
 * @param { 是否记录动作 } is_record
 */
export function loadAnime(Mixer, item, anime, duration = 1, is_record = true) {
  // 释放动画的所有内存, 重新加载动作
  Mixer.uncacheRoot(Mixer.getRoot());
  let animationClip = getItem(item).api.animations.find(animationClip => animationClip.name === anime);
  Mixer.clipAction(animationClip).setDuration(duration).play();
  if (is_record) lastAnime = anime;
}


/**
 * @function euler2quat
 * @param { direction } 欧拉向量
 */
export function euler2quat(direction) {
  let x = direction.x / 2,
    y = direction.y / 2,
    z = direction.z / 2;
  let sin = Math.sin,
    cos = Math.cos;
  let quat_x = sin(y) * sin(z) * cos(x) + cos(y) * cos(z) * sin(x);
  let quat_y = sin(y) * cos(z) * cos(x) - cos(y) * sin(z) * sin(x);
  let quat_z = sin(z) * cos(y) * cos(x) - sin(y) * cos(z) * sin(x);
  let quat_w = cos(x) * cos(z) * cos(x) + sin(y) * sin(z) * sin(x);
  let result = { x: quat_x, y: quat_y, z: quat_z, w: quat_w };
  return result;
}


/**
 * @function quat2euler
 * @param { direction } 四元数
 */
export function quat2euler(direction) {
  let x = direction.x,
    y = direction.y,
    z = direction.z,
    w = direction.w;
  let atan2 = Math.atan2,
    asin = Math.asin;
  let euler_x = atan2(2 * (w * x + y * z), (1 - 2 * (x * x + y * y)));
  let euler_y = asin(2 * (w * y - z * x));
  let euler_z = atan2(2 * (w * z + x * y), (1 - 2 * (y * y + z * z)));
  let result = { x: euler_x, y: euler_y, z: euler_z };
  return result;
}